﻿using ControlFocusWin.Biz;
using ControlFocusWin.Common;
using ControlFocusWin.Util;
using ControlFocusWin.WinUtilApi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ControlFocusWin
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    { 
        /// <summary>
        /// 屏幕像素转化为可见像素缩放因子
        /// </summary>
        public static ScreenScale SwitchScale = ScreenUtil.ZoomScale();

        /// <summary>
        /// 键盘 Hook 用于键盘输入拦截
        /// </summary>
        private KeyboardHook kh;

        /// <summary>
        /// 选择应用句柄
        /// </summary>
        private IntPtr currentAppHwnd;
         
        /// <summary>
        /// 存储捕获元素的位置信息
        /// </summary>
        private int elemXCoor = 0, elemYCoor = 0;

        /// <summary>
        /// 捕获鼠标所在位置
        /// </summary>
        private PixelPoint shiftPit;

        /// <summary>
        /// 捕获元素所在位置
        /// </summary>
        private PixelPoint ctrlPit;

        /// <summary>
        /// 捕获到的子元素
        /// </summary>
        private IntPtr captureElemHwnd;

        /// <summary>
        /// 用于缓存窗口标题
        /// </summary>
        private StringBuilder winTextBuffer = new StringBuilder(64); 

        public MainWindow()
        { 
            InitializeComponent();

            InitAppList();
        }


        private void InitAppList()
        {
            CALLBACK topWinCallback = new CALLBACK(GetTopWinAppName);
            Win32WindowApi.EnumWindows(topWinCallback, IntPtr.Zero);
        }
         
        /// <summary>
        /// 获取顶级窗口应用名，目前未过滤掉系统应用
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <param name="lparm">遍历时传入的参数</param>
        /// <returns></returns>
        public bool GetTopWinAppName(IntPtr hwnd, int lparm)
        {
            int pHwnd = Win32WindowApi.GetParent(hwnd);
            if (pHwnd == 0 && Win32WindowApi.IsWindowVisible(hwnd) && Win32WindowApi.IsWindowEnabled(hwnd))
            {
                winTextBuffer.Clear();
                Win32WindowApi.GetWindowText(hwnd, winTextBuffer, winTextBuffer.Capacity);
                if (winTextBuffer.Length != 0)
                {
                    appComboBox.Items.Add(winTextBuffer.ToString());
                    return true;
                }
            }
            return true;
        }
         
        private void Kh_OnKeyDownEvent(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            winTextBox.Text += Environment.NewLine + "*************************************" + Environment.NewLine;
            if (e.KeyCode == System.Windows.Forms.Keys.LShiftKey)
            {
                winTextBox.Text += "按下左 Shift 捕获鼠标所在位置" + Environment.NewLine;

                PixelPoint pit = new PixelPoint();
                Win32MouseApi.GetCursorPos(out pit);   //获取鼠标绝对位置

                winTextBox.Text += "获取到屏幕真实像素坐标： X = " + pit.X + ", Y = " + pit.Y + Environment.NewLine;

                elemXCoor = (int)(pit.X / SwitchScale.XScale);
                elemYCoor = (int)(pit.Y / SwitchScale.YScale);
                winTextBox.Text += "转换为真实显示可见坐标： X = " + elemXCoor + ", Y = " + elemYCoor + Environment.NewLine;

                shiftPit = pit;
            }
            else if (e.KeyCode == System.Windows.Forms.Keys.LControlKey)
            {
                winTextBox.Text += "按下左 Ctrl 捕获目标元素句柄" + Environment.NewLine;

                PixelPoint pit = new PixelPoint();
                Win32MouseApi.GetCursorPos(out pit);   //获取鼠标绝对位置

                winTextBox.Text += "获取到屏幕真实像素坐标： X = " + pit.X + ", Y = " + pit.Y + Environment.NewLine;

                captureElemHwnd = WindowBiz.FindWinByPoint(currentAppHwnd, pit);
                winTextBox.Text += "获取到子窗口句柄：handle = " + captureElemHwnd + Environment.NewLine;

                string title = WindowBiz.GetWinText(captureElemHwnd);
                winTextBox.Text += "获取到子窗口标题为：Title = " + title + Environment.NewLine;

                ctrlPit = pit;
            }
            else if (e.KeyCode == System.Windows.Forms.Keys.Tab)
            { 
                PixelPoint pit = new PixelPoint();
                Win32MouseApi.GetCursorPos(out pit);

                IntPtr inputElemHwnd = WindowBiz.FindWinByPoint(currentAppHwnd, pit);
                winTextBox.Text += "获取到子窗口句柄：handle = " + inputElemHwnd + Environment.NewLine;
                string title = WindowBiz.GetWinText(inputElemHwnd);
                winTextBox.Text += "获取到子窗口标题为：Title = " + title + Environment.NewLine;

                winTextBuffer.Clear();
                Win32WindowApi.SendMessageTextBox(inputElemHwnd, (int)WinMessageEnum.WM_SETTEXT, 0, winTextBuffer);
            }
            kh.UnHook();
        }

        /// <summary>
        /// 当前激活应用句柄
        /// </summary>
        private void ActiveBtn_Click(object sender, RoutedEventArgs e)
        {
            string appName = appComboBox.Items.Count > 0 ? (string)appComboBox.SelectedItem : "";
            if (string.IsNullOrEmpty(appName))
            {
                winTextBox.Text += $"请选择激活窗口" + Environment.NewLine;
                return;
            }

            currentAppHwnd = WindowBiz.FindWinByName(appName, IntPtr.Zero);

            WindowBiz.ActiveShowWin(currentAppHwnd);
             
            winTextBox.Text += $"激活并置顶显示窗口：{appName} . 句柄地址：" + currentAppHwnd + Environment.NewLine;
        }

        /// <summary>
        /// 设置窗口位置及大小
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SetWinBtn_Click(object sender, RoutedEventArgs e)
        {
            WindowBiz.SettingWinPosSize(currentAppHwnd);
             
            winTextBox.Text += "窗口移动到左上角（0,0），大小为：宽=650，高=500" + Environment.NewLine;
        }
         
        /// <summary>
        /// 获取所在位置元素句柄
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GetFirstElemBtn_Click(object sender, RoutedEventArgs e)
        {
            kh = new KeyboardHook();
            kh.SetHook();
            kh.OnKeyDownEvent += Kh_OnKeyDownEvent;
        }

        /// <summary>
        /// 通过鼠标位置进行元素操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GetSecondElemBtn_Click(object sender, RoutedEventArgs e)
        {
            kh = new KeyboardHook();
            kh.SetHook();
            kh.OnKeyDownEvent += Kh_OnKeyDownEvent;
        }

        /// <summary>
        /// 移动鼠标到目标位置，进行消息发送
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MoveMousePosBtn_Click(object sender, RoutedEventArgs e)
        {
            winTextBox.Text += "移动鼠标到 发送消息 按钮" + Environment.NewLine;
            winTextBox.Text += "通过捕获元素句柄利用SendMessage API在5秒后发送鼠标点击发送消息" + Environment.NewLine;
            Task.Run(() =>
            {
                Win32MouseApi.SetCursorPos(ctrlPit.X, ctrlPit.Y);
                System.Threading.Thread.Sleep(5000);
                WindowBiz.SendMsg(captureElemHwnd);

                this.Dispatcher.InvokeAsync(() =>
                {
                    winTextBox.Text += "移动鼠标到 清空消息 按钮" + Environment.NewLine;
                    winTextBox.Text += "通过捕获鼠标位置移动到目标元素在5秒后，再模拟鼠标点击" + Environment.NewLine;
                });

                Win32MouseApi.SetCursorPos(shiftPit.X, shiftPit.Y);
                System.Threading.Thread.Sleep(5000);
                MouseBiz.MouseLeftClick(shiftPit.X, shiftPit.Y);
            });
        }
         
        /// <summary>
        /// 刷新打开应用窗口列表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RefreshBtn_Click(object sender, RoutedEventArgs e)
        {
            appComboBox.Items.Clear();
            InitAppList();
        }

        /// <summary>
        /// 清空显示记录
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            winTextBox.Text = "";
        }
         
        private void ShowFlowOperMsg(string infoStr)
        {
            this.Dispatcher.BeginInvoke((Action<string>)((msg) =>
            {
                winTextBox.Text += msg + Environment.NewLine; ;
            }), infoStr);
        }

        /// <summary>
        /// 遍历所有子窗口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EnumWinBtn_Click(object sender, RoutedEventArgs e)
        {
            //IntPtr dstHwnd = Win32WindowApi.FindWindow(null, "Form1");

            //1. 通过父窗口，第一个子窗口 获取 其它子窗口
            //IntPtr childTopWin = (IntPtr)0x001B09D2;
            //IntPtr childHwnd = Win32WindowApi.FindWindowEx(dstHwnd, childTopWin, null, "发送消息");

            //2. 遍历桌面顶级窗口
            //Win32WindowApi.EnumWindows(EnumChildWinCallback, dstHwnd);

            //3. 遍历一个窗口中所有子窗口
            Win32WindowApi.EnumChildWindows(currentAppHwnd, EnumChildWinCallback, IntPtr.Zero);

            //4. 获取当前窗口中第一个子窗口
            //IntPtr childHwnd = Win32WindowApi.GetTopWindow(dstHwnd);

            //PixelPoint pit;
            //pit.X = 248;
            //pit.Y = 185;
            //IntPtr childHwnd = Win32WindowApi.ChildWindowFromPoint(dstHwnd, pit);

            //var sb = new StringBuilder(300);
            //Win32WindowApi.GetWindowText(childHwnd, sb, sb.Capacity);
            //winTextBox.Text += "子窗口为 = " + sb.ToString() + Environment.NewLine;
        }

        /// <summary>
        /// 清空其它窗口输入文本框
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearMsgBtn_Click(object sender, RoutedEventArgs e)
        {
            kh = new KeyboardHook();
            kh.SetHook();
            kh.OnKeyDownEvent += Kh_OnKeyDownEvent;
        }

        /// <summary>
        /// 遍历子窗口回调函数
        /// </summary>
        /// <param name="hwnd">获取到当前子窗口句柄</param>
        /// <param name="lparm">传入参数值</param>
        /// <returns></returns>
        public bool EnumChildWinCallback(IntPtr hwnd, int lparm)
        {
            winTextBuffer.Clear();
            Win32WindowApi.GetWindowText(hwnd, winTextBuffer, winTextBuffer.Capacity);

            string winText = winTextBuffer.ToString();
            this.Dispatcher.InvokeAsync(()=>
            {
                winTextBox.Text += "hwnd = " + winText + Environment.NewLine;
            });
             
            return true;
        }

    }
}
